package com.alibaba.citrus.cr.sales.plan.facade.service.salesplan.adjust;

import com.alibaba.citrus.cr.common.annotation.EpochTransactional;
import com.alibaba.citrus.cr.common.annotation.FacadeInvoker;
import com.alibaba.citrus.cr.common.exception.FacadeException;
import com.alibaba.citrus.cr.sales.plan.api.salesplan.audit.SalesPlanAdjustSendWxMessageService;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.PageQueryPlanScItemStatRequest;
import com.alibaba.citrus.cr.sales.plan.functions.salesplan.SalesPlanEntity;
import com.alibaba.citrus.cr.sales.plan.functions.salesplan.adjust.SalesPlanAdjustDetailAbility;
import com.alibaba.citrus.cr.sales.plan.model.SalesPlanLineStatusEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanCheckStatusEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanModelEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesPlanStatusEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.SalesStatBizTypeEnum;
import com.alibaba.citrus.cr.sales.plan.model.enums.StatPoolTypeEnum;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanLineRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanScItemExtendRepository;
import com.alibaba.citrus.cr.sales.plan.repository.SalesPlanScItemStatRepository;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanAdjustDetailSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanLineSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanSDO;
import com.alibaba.citrus.cr.sales.plan.api.salesplan.adjust.SalesPlanAdjustWriteService;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.PageQueryPlanLineRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.PageQuerySalePlanRequest;
import com.alibaba.citrus.cr.sales.plan.dto.api.request.QuerySalesPlanRequest;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanScItemExtendSDO;
import com.alibaba.citrus.cr.sales.plan.sdo.SalesPlanStatScItemSDO;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.cz.base.tool.page.PageResult;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.alibaba.lattice2.epoch.tenant.DefaultTenant;
import com.alibaba.ttl.TtlRunnable;
import com.epoch.app.bcorder.sales_plan.planscitemextend.model.PlanScItemExtend;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author yuhailin
 * @description:
 * @date 2021-10-25 15:49
 */
@Service
public class SalesPlanAdjustWriteServiceImpl implements SalesPlanAdjustWriteService {
    private final Log log = Log.getLogger(SalesPlanAdjustWriteServiceImpl.class);

    @Resource
    SalesPlanRepository salesPlanRepository;

    @Resource
    SalesPlanLineRepository salesPlanLineRepository;

    @Resource
    SalesPlanAdjustDetailAbility salesPlanAdjustDetailAbility;

    @Resource
    SalesPlanScItemStatRepository salesPlanScItemStatRepository;

    @Resource
    SalesPlanScItemExtendRepository salesPlanScItemExtendRepository;

    @Resource
    SalesPlanAdjustSendWxMessageService wxMessageService;

    /**
     * 计划明细page_size
     */
    private static final Integer SALES_PLAN_LIN_PAGE_SIZE = 500;


    @Override
    @FacadeInvoker
    @EpochTransactional(appCode = "bc_order", dataSourceCode = "cr_ots", dataSourceType = "app")
    public Result<SalesPlanSDO> createSalesPlanAdjust(SalesPlanSDO salesPlanSDO) {
        //校验时间
        Result result = checkParameter(salesPlanSDO);
        if (result != null) return result;
        //校验计划是否存在正在调整中的数据
        checkIsAdjust(salesPlanSDO);

        QuerySalesPlanRequest querySalesPlanRequest = new QuerySalesPlanRequest();
        querySalesPlanRequest.setId(salesPlanSDO.getId().toString());
        SalesPlanSDO load = salesPlanRepository.load(querySalesPlanRequest);
        if (Objects.isNull(load)) {
            throw new FacadeException("OTS-02-002-00-16-001");
        }
        SalesPlanSDO sdo = new SalesPlanSDO();
        BeanUtils.copyProperties(load, sdo);
        sdo.setParentId(load.getId().intValue());
        sdo.setId(null);
        sdo.setCreator(null);
        sdo.setUpdater(null);
        sdo.setGmtCreate(null);
        sdo.setGmtModified(null);
        sdo.setCheckStatus(SalesPlanCheckStatusEnum.INIT_DRAFT.getCode());
        sdo.setModel(SalesPlanModelEnum.ADJUST_MODEL.getModel());
        sdo.setStatus(SalesPlanStatusEnum.ADJUST.getCode());
        sdo.setStartTime(salesPlanSDO.getStartTime());
        sdo.setEndTime(salesPlanSDO.getEndTime());
        sdo.setMonthFirst(salesPlanSDO.getMonthFirst());
        sdo.setMonthMiddle(salesPlanSDO.getMonthMiddle());
        sdo.setMonthLast(salesPlanSDO.getMonthLast());
        sdo.setPlanNotice(salesPlanSDO.getPlanNotice());
        // 创建月度调整
        SalesPlanEntity salesPlanAdjustEntity = SalesPlanEntity.of(sdo);
        String lastInsertId = salesPlanAdjustEntity.save();

        if (Integer.parseInt(lastInsertId) > 0) {
            //获取计划明细总条数
            PageQueryPlanLineRequest queryPlanLineRequest = new PageQueryPlanLineRequest();
            queryPlanLineRequest.setPlanId(salesPlanSDO.getId().toString());
            queryPlanLineRequest.setStatus(SalesPlanLineStatusEnum.FINISH.getStatus());
            PageResult<List<SalesPlanLineSDO>> totalResult = salesPlanLineRepository.pageQuerySalesPlanLineList(queryPlanLineRequest);
            int totalPage = (totalResult.getTotal() + SALES_PLAN_LIN_PAGE_SIZE - 1) / SALES_PLAN_LIN_PAGE_SIZE;
            //新增调整明细
            List<SalesPlanAdjustDetailSDO> salesPlanAdjustDetailSDOList = new ArrayList<>();
            for (int i = 1; i <= totalPage; i++) {
                queryPlanLineRequest.setSize(SALES_PLAN_LIN_PAGE_SIZE);
                queryPlanLineRequest.setPage(i);
                PageResult<List<SalesPlanLineSDO>> listPageResult = salesPlanLineRepository.pageQuerySalesPlanLineList(queryPlanLineRequest);
                if (CollectionUtils.isEmpty(listPageResult.getContent())) {
                    break;
                }
                listPageResult.getContent().stream().forEach(salesPlanLineSDO -> {
                    SalesPlanAdjustDetailSDO salesPlanAdjustDetailSDO = SalesPlanAdjustDetailSDO.builder().build();
                    BeanUtils.copyProperties(salesPlanLineSDO, salesPlanAdjustDetailSDO);
                    salesPlanAdjustDetailSDO.setAdjustId(Long.valueOf(lastInsertId));
                    salesPlanAdjustDetailSDO.setPlanDetailId(salesPlanLineSDO.getId());
                    salesPlanAdjustDetailSDO.setPlanId(salesPlanSDO.getId().toString());
                    salesPlanAdjustDetailSDO.setStatus(SalesPlanLineStatusEnum.FINISH.getStatus());
                    salesPlanAdjustDetailSDO.setId(null);
                    salesPlanAdjustDetailSDO.setCreator(null);
                    salesPlanAdjustDetailSDO.setUpdater(null);
                    salesPlanAdjustDetailSDO.setGmtCreate(null);
                    salesPlanAdjustDetailSDO.setGmtModified(null);
                    //调整量置0
                    salesPlanAdjustDetailSDO.setAdjustCount(0);
                    salesPlanAdjustDetailSDO.setMonthFirstAdjustCount(0);
                    salesPlanAdjustDetailSDO.setMonthMiddleAdjustCount(0);
                    salesPlanAdjustDetailSDO.setMonthLastAdjustCount(0);
                    salesPlanAdjustDetailSDO.setMonthFirstAdjustReturnCount(0);
                    salesPlanAdjustDetailSDO.setMonthMiddleAdjustReturnCount(0);
                    salesPlanAdjustDetailSDO.setMonthLastAdjustReturnCount(0);
                    salesPlanAdjustDetailSDO.setMonthFirstAdjustTotalCount(0);
                    salesPlanAdjustDetailSDO.setMonthMiddleAdjustTotalCount(0);
                    salesPlanAdjustDetailSDO.setMonthLastAdjustTotalCount(0);
                    salesPlanAdjustDetailSDO.setAdjustMoney(0L);
                    salesPlanAdjustDetailSDO.setBeforeAdjustMoney(0L);
                    salesPlanAdjustDetailSDOList.add(salesPlanAdjustDetailSDO);
                });
            }
            String successCount = salesPlanAdjustDetailAbility.batchCreateSalesPlanAdjustDetail(salesPlanAdjustDetailSDOList);
            if(Integer.valueOf(successCount) > 0){
                //修改月度计划状态
                SalesPlanSDO planSDO = new SalesPlanSDO();
                planSDO.setId(load.getId());
                planSDO.setStatus(SalesPlanStatusEnum.ADJUST.getCode());
                SalesPlanEntity salesPlanEntity = SalesPlanEntity.of(planSDO);
                salesPlanEntity.updateSalesPlanStatus();
            }

            // 不阻断流程就走异步 低频操作不启线程池
            new Thread(decorateTenantCode(() -> {
                long start = System.currentTimeMillis();
                //调整时发送微信小程序通知，发送失败也不阻断流程，打印错误日志
                try {
                    log.info("Start_sendWxSubscribeMessage:{}", load.getId());
                    wxMessageService.sendWxSubscribeMessage(String.valueOf(load.getId()));
                } catch (Exception e) {
                    log.error("SendAdjustWxMessage_Failed:{}", load.getId(), e);
                } finally {
                    log.info("wxMessageService.sendWxSubscribeMessage cost:" + (System.currentTimeMillis() - start));
                }
            })).start();

            sdo.setId(Long.valueOf(lastInsertId));
            return Result.success(sdo);
        }
        return Result.fail("OTS-02-007-00-16-999","系统开小差了，请重试！");
    }

    @Nullable
    private Result checkParameter(SalesPlanSDO salesPlanSDO) {
        //开始结束时间不能为空
        if (null == salesPlanSDO.getStartTime() || null == salesPlanSDO.getEndTime()) {
            Result result = new Result();
            result.setSuccess(false);
            Map<String, Object> validateErrors = new HashMap<>();
            validateErrors.put("adjustTime", "调整起止时间 是必填字段");
            result.setValidateErrors(validateErrors);
            return result;
        }

        //提报开始时间不能小于当前时间
        if (null != salesPlanSDO.getStartTime()) {
            //当前时间
            Date currentTime = new Date();
            Date startTime = salesPlanSDO.getStartTime();
            int compareTo = startTime.compareTo(currentTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("adjustTime", "调整开始时间应在当前时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }

        //提报结束不能小于当前时间
        if (null != salesPlanSDO.getEndTime()) {
            //当前时间
            Date currentTime = new Date();
            Date endTime = salesPlanSDO.getEndTime();
            int compareTo = endTime.compareTo(currentTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("adjustTime", "调整开始时间应在当前时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }

        //提报结束时间不能大于提报开始时间
        if (null != salesPlanSDO.getStartTime() && null != salesPlanSDO.getEndTime()) {
            Date startTime = salesPlanSDO.getStartTime();
            Date endTime = salesPlanSDO.getEndTime();
            int compareTo = endTime.compareTo(startTime);
            if (compareTo < 0) {
                Result result = new Result();
                result.setSuccess(false);
                Map<String, Object> validateErrors = new HashMap<>();
                validateErrors.put("adjustTime", "调整结束时间应在调整开始时间之后");
                result.setValidateErrors(validateErrors);
                return result;
            }
        }
        return null;
    }

    private void checkIsAdjust(SalesPlanSDO salesPlanSDO) {
        PageQuerySalePlanRequest pageQuerySalePlanRequest = new PageQuerySalePlanRequest();
        pageQuerySalePlanRequest.setParentId(salesPlanSDO.getId().toString());
        pageQuerySalePlanRequest.setModel(SalesPlanModelEnum.ADJUST_MODEL.getModel());
//        pageQuerySalePlanRequest.setStatus(SalesPlanStatusEnum.ADJUST.getCode().toString());
        pageQuerySalePlanRequest.setStatusList(Lists.newArrayList(SalesPlanStatusEnum.ADJUST.getCode(), SalesPlanStatusEnum.ADJUSTED_TO_BE_REPLIED.getCode(), SalesPlanStatusEnum.ADJUSTED_TO_BE_PUBLISHED.getCode()));
        PageResult<List<SalesPlanSDO>> listPageResult1 = salesPlanRepository.pageQuery(pageQuerySalePlanRequest);
        if (listPageResult1.getContent().size() > 0) {
            throw new FacadeException("OTS-02-005-00-15-015");
        }
    }

    /**
     * 多租户开发场景下异步线程池中调用需要包装租户code
     * @param runnable
     * @return
     */
    private @NotNull Runnable decorateTenantCode(Runnable runnable) {
        String tenantCode = DefaultTenant.get();
        return TtlRunnable.get(() -> DefaultTenant.runInScope(tenantCode, runnable));
    }


}
